// XcpControlHost.cpp : Implementation of CXcpControlHost

#include "stdafx.h"
#include "../LoAg.h"
#include "Ocidl.h"
#include "LoAg_i.h"
//#include "atlstr.h"
#import "libid:283C8576-0726-4DBC-9609-3F855162009A" version("4.0")

class CXcpPropertyBag:IPropertyBag
{
public:
	CXcpPropertyBag(){m_nRef=0;}
	~CXcpPropertyBag(){}

	HRESULT _stdcall QueryInterface(REFIID iid, void** ppvObject)
	{
		return S_OK;
	}

	ULONG _stdcall AddRef()
	{
		return ++m_nRef;
	}
	
	ULONG _stdcall Release()
	{
		if(--m_nRef == 0)
			delete this;

		return m_nRef;
	}

	ULONG m_nRef;

	STDMETHOD (Read)(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog)
	{
		HRESULT hr = E_INVALIDARG;
		BSTR bstrValue = NULL;
	  
		if (_wcsicmp(pszPropName, L"Source") == 0) 
		{
			bstrValue = SysAllocString(L"SilverlightTestApp.xap");
			//bstrValue = SysAllocString(L"application.xap");
		}    
		else if (_wcsicmp(pszPropName, L"Background") == 0) 
		{
			bstrValue = SysAllocString(L"#FFFFFF");
		}

		else if (_wcsicmp(pszPropName, L"Windowless") == 0) 
		{
			V_VT(pVar) = VT_BOOL;
			V_BOOL(pVar) = VARIANT_FALSE;
			hr = S_OK;
		}
		/*else if (_wcsicmp(pszPropName, L"EnableHtmlAccess") == 0) 
		{
			V_VT(pVar) = VT_BOOL;
			V_BOOL(pVar) = VARIANT_TRUE;
			hr = S_OK;
		}*/

		if (bstrValue != NULL) 
		{
			V_VT(pVar) = VT_BSTR;
			V_BSTR(pVar) = bstrValue;
			hr = S_OK;
		}
		return hr;
	}

	
	STDMETHOD (Write)(LPCOLESTR pszPropName, VARIANT *pVar)
	{
		return S_OK;
	}
};

/*!
\brief This class creates a Silverlight container.
*/
class CXcpControlHost : public CAxHostWindow, public IXcpControlHost3
{
	// Extra definitions
/*	HWND			m_hWnd;
	IUnknown		*m_spUnknown;
	IOleObject		*m_spOleObject;
	DWORD			m_dwMiscStatus;
	DWORD			m_dwViewObjectType;
	IViewObjectEx	*m_spViewObject;
	DWORD			m_dwOleObject;
	SIZEL			m_hmSize;
	SIZEL			m_pxSize;
	RECT			m_rcPos;
	void	ReleaseAll()
	{

	}*/
public:
	CXcpControlHost();
	~CXcpControlHost();

	typedef enum
	{
		XcpHostOption_FreezeOnInitialFrame       = 0x001,
		XcpHostOption_DisableFullScreen          = 0x002,
		XcpHostOption_DisableManagedExecution    = 0x008,
		XcpHostOption_EnableCrossDomainDownloads = 0x010,
		XcpHostOption_UseCustomAppDomain         = 0x020,
		XcpHostOption_DisableNetworking          = 0x040,        
		XcpHostOption_DisableScriptCallouts      = 0x080,
		XcpHostOption_EnableHtmlDomAccess        = 0x100,
		XcpHostOption_EnableScriptableObjectAccess = 0x200,
		XcpHostOption_EnableAssemblySharing		 = 0x800,
		XcpHostOption_HookGetComAutomationObject = 0x1000,
		XcpHostOption_EnableElevatedPermissions	 = 0x2000,
		XcpHostOption_EnableWindowlessAccessibility	= 0x4000
	} XcpHostOptions;

	static HWND hControlWindow;
	static IUnknown* pUnKnown;
	static XcpControlLib::IXcpControl2* pControl;

	// IXcpControlHost implementation declarations
	STDMETHOD(GetHostOptions)(DWORD* pdwOptions)
	{
		*pdwOptions = XcpHostOption_EnableCrossDomainDownloads
			| XcpHostOption_EnableScriptableObjectAccess | XcpHostOption_EnableHtmlDomAccess
			| XcpHostOption_EnableAssemblySharing | XcpHostOption_HookGetComAutomationObject
			| XcpHostOption_EnableElevatedPermissions;
		return S_OK;
	}

	STDMETHOD(NotifyLoaded)()
	{
		return S_OK;
	}

	STDMETHOD(NotifyError)(BSTR bstrError, BSTR bstrSource, long nLine, long nColumn)
	{
		MessageBox( bstrError, bstrSource );
		return S_OK;
	}

	STDMETHOD(GetNamedSource)(BSTR bstrSourceID, BSTR* pbstrSource)
	{    
		return E_NOTIMPL;
	}
	STDMETHOD(DownloadUrl)(BSTR bstrUrl, IXcpControlDownloadCallback* pCallback, IStream** ppStream)
	{
		//	MessageBox(L"DownloadUrl", L"DownloadUrl", 0);
		return S_FALSE;
	}
	STDMETHOD(GetCustomAppDomain)(IUnknown** ppAppDomain)
	{  
		return S_FALSE;
	}
	STDMETHOD(InvokeHandler)(BSTR bstrName, VARIANT varParam1, VARIANT varParam2, VARIANT* pvarResult)
	{
		::MessageBox( hControlWindow, NULL, bstrName, MB_OK );
		return E_NOTIMPL;
	}
	STDMETHOD(GetBaseUrl)(BSTR* pbstrUrl)
	{
		TCHAR currentDirectory[256];
		GetCurrentDirectory( 255, currentDirectory);
		for( int i = 0; currentDirectory[i]; ++i )
		{
			if( currentDirectory[i] == '\\')
				currentDirectory[i] = '/';
		}
		wcscat_s( currentDirectory, L"/SilverlightTestApp/bin/Debug/" );
		*pbstrUrl = SysAllocString( currentDirectory );
		//*pbstrUrl = SysAllocString(L"C:\\Users\\jordan\\Local Settings\\Application data\\Microsoft\\Silverlight\\OutOfBrowser\\2168639641.localhost");
		return S_OK;
	}

	STDMETHOD(GetControlVersion)(UINT *puMajorVersion, UINT *puMinorVersion)
	{
		*puMajorVersion = 4;
		*puMinorVersion = 50401;
		return S_OK;;
	}


	STDMETHOD(GetDefaultThemeXaml)(BSTR assemblyName, LPBSTR pbstrXaml)
	{
		*pbstrXaml = NULL;
		return S_OK;
	}
	STDMETHOD(GetDefaultPortableUserInterfaceFontInfo)(LPBSTR pbstrCompositeFont)
	{
		*pbstrCompositeFont = NULL;
		return S_OK;
	}
	// bstrProgId = filename.CLSID
	STDMETHOD(GetComAutomationObject)(BSTR bstrProgId,DWORD dwFlags,IDispatch **ppDisp)
	{
		if( '\0' == *bstrProgId )
		{
			*ppDisp = iDispatchSilverlightInterface;
			return S_OK;
		}
		return S_FALSE;	// Use the default method of creating a COM interface
	}

	DECLARE_NOT_AGGREGATABLE(CXcpControlHost);

	BEGIN_COM_MAP(CXcpControlHost)
	COM_INTERFACE_ENTRY(IXcpControlHost3)
	COM_INTERFACE_ENTRY_CHAIN(CAxHostWindow)
	END_COM_MAP()

	BEGIN_MSG_MAP(CXcpControlHost)
	CHAIN_MSG_MAP(CAxHostWindow)
	END_MSG_MAP()

	//IServiceProvider Implementation
	STDMETHOD(QueryService)(REFGUID rsid, REFIID riid, void** ppvObj);

	// ATL Overrides
	STDMETHOD(AttachControl)(IUnknown* pUnkControl, HWND hWnd);
	HRESULT ActivateXcpControl(IUnknown* pUnkControl);

	DECLARE_REGISTRY_RESOURCEID(IDR_XCPCONTROLHOST)
};

OBJECT_ENTRY_AUTO(__uuidof(XcpControlHost), CXcpControlHost)


 HWND CXcpControlHost::hControlWindow = NULL;
 IUnknown* CXcpControlHost::pUnKnown = NULL;
 XcpControlLib::IXcpControl2* CXcpControlHost::pControl = NULL;


///////////////////////////////////////////////////////////////////////////////
// CXcpControlHost IXcpControlHost Implementation



///////////////////////////////////////////////////////////////////////////////
// CXcpControlHost Constructor/Destructor

CXcpControlHost::CXcpControlHost() 
{
}

CXcpControlHost::~CXcpControlHost() 
{
}



///////////////////////////////////////////////////////////////////////////////
// CXcpControlHost IServiceProvider Implementation

STDMETHODIMP CXcpControlHost::QueryService(REFGUID rsid, REFIID riid, void** ppvObj)
{
    ATLASSERT(ppvObj != NULL);
    if (ppvObj == NULL)
        return E_POINTER;
    *ppvObj = NULL;

	//static const GUID IID_IXcpControlHost = 
	//	{ 0x1B36028E, 0xB491, 0x4bb2, { 0x85, 0x84, 0x8A, 0x9E, 0x0A, 0x67, 0x7D, 0x6E }};

    HRESULT hr = E_NOINTERFACE;

    if ((rsid == IID_IXcpControlHost) && (riid == IID_IXcpControlHost))
	{
        ((IXcpControlHost*)this)->AddRef();
        *ppvObj = (IXcpControlHost*)this;
        hr = S_OK;
    }

	if ((rsid == IID_IXcpControlHost2) && (riid == IID_IXcpControlHost2))
	{
        ((IXcpControlHost2*)this)->AddRef();
        *ppvObj = (IXcpControlHost2*)this;
        hr = S_OK;
    }

	if ((rsid == IID_IXcpControlHost3) && (riid == IID_IXcpControlHost3))
	{
		((IXcpControlHost3*)this)->AddRef();
		*ppvObj = (IXcpControlHost3*)this;
		hr = S_OK;
	}

    return hr;
}

///////////////////////////////////////////////////////////////////////////////
// General ActiveX control embedding.


STDMETHODIMP CXcpControlHost::AttachControl(IUnknown* pUnKnown, HWND hWnd)
{
    ReleaseAll();

    HRESULT hr = S_FALSE;
    BOOL fReleaseWindowOnFailure = FALSE;

    if ((m_hWnd != NULL) && (m_hWnd != hWnd))
	{
        // Don't release the window if it's the same as the one we already subclass/own
		::RedrawWindow( m_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_INTERNALPAINT | RDW_FRAME );
        //ReleaseWindow() -- Also unsubclasses if needed.
		::DestroyWindow( m_hWnd );
    }

    if (::IsWindow(hWnd))
	{
        if (m_hWnd != hWnd)
		{
            // Don't need to subclass the window if we already own it
            SubclassWindow(hWnd);
            fReleaseWindowOnFailure = TRUE;
        }

        hr = ActivateXcpControl(pUnKnown);
        if (FAILED(hr))
		{
            ReleaseAll();

            if (m_hWnd != NULL)
			{
				::RedrawWindow( m_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_INTERNALPAINT | RDW_FRAME );

                if (fReleaseWindowOnFailure)
				{
                    // We sub-classed the window in an attempt to create this control, so we unsubclass on failure
                    //ReleaseWindow();
					::DestroyWindow( m_hWnd );
                }
            }
        }
    }
    return hr;
}

HRESULT CXcpControlHost::ActivateXcpControl(IUnknown* pUnKnown) 
{
    if (pUnKnown == NULL)
	{
        return S_OK;
    }

    m_spUnknown = pUnKnown;

    HRESULT hr = S_OK;
    pUnKnown->QueryInterface(__uuidof(IOleObject), (void**)&m_spOleObject);
    if (m_spOleObject) 
	{
        //m_spOleObject->GetMiscStatus(DVASPECT_CONTENT, &m_dwMiscStatus);
		OleRegGetMiscStatus( __uuidof(m_spOleObject), DVASPECT_CONTENT, &m_dwMiscStatus );
        if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST) 
		{
            //CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
			IOleClientSite	*spClientSite = NULL;
			((ATL::CAxHostWindow *)this)->QueryInterface( __uuidof(IOleClientSite), (void **)&spClientSite );
			if( NULL != spClientSite )
			{
				m_spOleObject->SetClientSite(spClientSite);
				spClientSite->Release();
			}
        }

        //CComQIPtr<IPersistPropertyBag> pPersist(m_spOleObject);
		IPersistPropertyBag	*pPersist = NULL;
		m_spOleObject->QueryInterface( __uuidof(IPersistPropertyBag), (void **)&pPersist );

        if ( NULL != pPersist ) 
		{
            IPropertyBag* pPropBag = (IPropertyBag*)new CXcpPropertyBag();
            pPropBag->AddRef();

            pPersist->Load((IPropertyBag*)pPropBag, NULL);
            pPropBag->Release();
        }

        if (0 == (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)) 
		{
            //CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
			IOleClientSite	*spClientSite = NULL;
			((ATL::CAxHostWindow *)this)->QueryInterface(  __uuidof(IOleClientSite), (void **)&spClientSite);
			//GetControllingUnknown()->QueryInterface( __uuidof(IOleClientSite), (void **)&spClientSite );
			if( NULL != spClientSite )
			{
				m_spOleObject->SetClientSite(spClientSite);
				spClientSite->Release();
			}
        }

        m_dwViewObjectType = 0;
        hr = m_spOleObject->QueryInterface(__uuidof(IViewObjectEx), (void**) &m_spViewObject);
        if (FAILED(hr)) 
		{
            hr = m_spOleObject->QueryInterface(__uuidof(IViewObject2), (void**) &m_spViewObject);
            if (SUCCEEDED(hr))
			{
                m_dwViewObjectType = 3;
            }
        }
        else
		{
            m_dwViewObjectType = 7;
        }

        if (FAILED(hr)) 
		{
            hr = m_spOleObject->QueryInterface(__uuidof(IViewObject), (void**) &m_spViewObject);
            if (SUCCEEDED(hr))
			{
                m_dwViewObjectType = 1;
			}
        }

        //CComQIPtr<IAdviseSink> spAdviseSink(GetControllingUnknown());
		IAdviseSink *spAdviseSink = NULL;
		//GetControllingUnknown()->QueryInterface( __uuidof(IAdviseSink), (void **)&spAdviseSink );
		((ATL::CAxHostWindow *)this)->QueryInterface( __uuidof(IAdviseSink), (void **)&spAdviseSink );
		if( NULL != spAdviseSink )
		{
			m_spOleObject->Advise(spAdviseSink, &m_dwOleObject);
			if (m_spViewObject) 
			{
				m_spViewObject->SetAdvise(DVASPECT_CONTENT, 0, spAdviseSink);
			}
			spAdviseSink->Release();
		}

        m_spOleObject->SetHostNames(OLESTR("AXWIN"), NULL);

        if ((m_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME) == 0) 
		{
			m_spOleObject->GetExtent( DVASPECT_CONTENT, &m_hmSize );
            m_pxSize.cx =  m_rcPos.right - m_rcPos.left;
            m_pxSize.cy =  m_rcPos.bottom - m_rcPos.top;
            AtlPixelToHiMetric(&m_pxSize, &m_hmSize);
            m_spOleObject->SetExtent(DVASPECT_CONTENT, &m_hmSize);
            m_spOleObject->GetExtent(DVASPECT_CONTENT, &m_hmSize);
            AtlHiMetricToPixel(&m_hmSize, &m_pxSize);
            m_rcPos.right = m_rcPos.left + m_pxSize.cx ;
            m_rcPos.bottom = m_rcPos.top + m_pxSize.cy ;
            //CComQIPtr<IOleClientSite> spClientSite(GetControllingUnknown());
			IOleClientSite *spClientSite = NULL;
			//GetControllingUnknown()->QueryInterface( __uuidof(IOleClientSite), (void **)&spClientSite );
			((ATL::CAxHostWindow *)this)->QueryInterface( __uuidof(IOleClientSite), (void **)&spClientSite );
			if( NULL != spClientSite )
			{
				m_rcPos.left = m_rcPos.top = 0;
				m_rcPos.right = m_hmSize.cx;
				m_rcPos.bottom = m_hmSize.cy;
				hr = m_spOleObject->DoVerb( OLEIVERB_INPLACEACTIVATE, NULL, spClientSite, 0, m_hWnd, &m_rcPos );
				::RedrawWindow( m_hWnd, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_INTERNALPAINT | RDW_FRAME );
				spClientSite->Release();
			}
        }
		if( NULL != pPersist )
		{
			pPersist->Release();
		}
    }

    //CComPtr<IObjectWithSite> spSite;
	IObjectWithSite		*spSite = NULL;
    pUnKnown->QueryInterface(__uuidof(IObjectWithSite), (void**)&spSite);
    if ( NULL != spSite ) 
	{
//        spSite->SetSite(GetControllingUnknown());
		IUnknown *iUnknown = NULL;
		((ATL::CAxHostWindow *)this)->QueryInterface( __uuidof(IUnknown), (void **)&iUnknown );
		spSite->SetSite( iUnknown );
		spSite->Release();
    }

    return hr;
}


////////////////// External calls


/*!
\brief Creates a XCP control container
@param[in]	hWnd	Already created control container.  Static control.
\retval HANDLE	XcpControlHost
*/
HRESULT LoAgXcpCreateControl( HWND hWnd ) 
{
	AtlAxWinInit();

	HRESULT hr;
	static const GUID IID_IXcpControl = { 0x1FB839CC, 0x116C, 0x4C9B, { 0xAE, 0x8E, 0x3D, 0xBB, 0x64, 0x96, 0xE3, 0x26 }};
	static const GUID CLSID_XcpControl = { 0xDFEAF541, 0xF3E1, 0x4c24, { 0xAC, 0xAC, 0x99, 0xC3, 0x07, 0x15, 0x08, 0x4A }};
	static const GUID IID_IXcpControl2 = { 0x1c3294f9, 0x891f, 0x49b1, { 0xBB, 0xAE, 0x49, 0x2a, 0x68, 0xBA, 0x10, 0xcc }};

	//	static const GUID CLSID_XcpControl2 = 
	//		{ 0xDFEAF541, 0xF3E1, 0x4c24, { 0xAC, 0xAC, 0x99, 0xC3, 0x07, 0x15, 0x08, 0x4A }};

	//static const GUID IID_IXcpControlHost2 = 
	//	{ 0xfb3ed7c4, 0x5797, 0x4b44, { 0x86, 0x95, 0x0c, 0x51, 0x2e, 0xa2, 0x7D, 0x8f }};

	hr = CoCreateInstance(CLSID_XcpControl, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&CXcpControlHost::pUnKnown);

	if (SUCCEEDED(hr)) 
	{
		//CComPtr<IUnknown> spUnkContainer;
		IUnknown	*spUnkContainer = NULL;
		//CoCreateInstance( __uuidof(IUnknown), &CXcpControlHost::pUnKnown, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&spUnkContainer );
		hr = CXcpControlHost::_CreatorClass::CreateInstance(NULL, IID_IUnknown, (void**)&spUnkContainer);
		
		if (SUCCEEDED(hr)) 
		{
			//CComPtr<IAxWinHostWindow> pAxWindow;
			IAxWinHostWindow	*pAxWindow = NULL;

			spUnkContainer->QueryInterface(IID_IAxWinHostWindow, (void**)&pAxWindow);
			if( NULL != pAxWindow )
			{
				CXcpControlHost::pUnKnown->QueryInterface(IID_IXcpControl2, (void**)&CXcpControlHost::pControl);
				hr = pAxWindow->AttachControl(CXcpControlHost::pUnKnown, hWnd);            
			}
			CXcpControlHost::hControlWindow = hWnd;

			IOleInPlaceActiveObject *pObj;
			hr = CXcpControlHost::pControl->QueryInterface(IID_IOleInPlaceActiveObject, (void**)&pObj);
			spUnkContainer->Release();
		}
	}
	return hr;
}

HRESULT LoAgXcpDestroyControl()
{
	HRESULT hr = S_OK;
	if (CXcpControlHost::pControl)
	{
		CXcpControlHost::pControl->Release();
	}
	if (CXcpControlHost::pUnKnown)
	{
		CXcpControlHost::pUnKnown->Release();
	}
	return hr;
}

